package com.coffee.websocket;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.coffee.websocket.command.CommandModelMapping;
import com.coffee.websocket.handler.*;
import com.coffee.websocket.metadata.MochaMessageType;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import com.coffee.websocket.metadata.MochaServerParameter;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author songkui
 * @since 2024/3/16 10:35
 */
@Slf4j
public class MochaWebSocketServer {

    public void start(Integer port, String host){
        start(port, host, HandlerMapping.getHandlerParameter());
    }

    public void start(Integer port, String host, WebsocketHandlerParameter handlerParameter) {
        final SocketIOServer server = new SocketIOServer(buildConfiguration(port, host));
        MochaWebSocketExecutor.getInstance().start();
        Set<MochaServerParameter> paramList = CommandModelMapping.getServerParamSet();
        if (CollectionUtil.isEmpty(paramList)){
            throw new MochaWebsocketException("MochaServerParameter  is null");
        }


        server.addConnectListener(client -> {
            log.info("Connect client sessionId : {}; RemoteAddress {}", client.getSessionId(), client.getRemoteAddress().toString());
            Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
            MochaSocketConnectHandler handler = handlerParameter.getSocketConnectHandler();
            handler.connect(params, client);
        });

        server.addDisconnectListener(client -> {
            log.info("Disconnect client sessionId : {}; RemoteAddress {}", client.getSessionId(), client.getRemoteAddress().toString());
            MochaSocketCloseHandler closeHandler = handlerParameter.getSocketCloseHandler();
            closeHandler.close(client);
        });


        for (MochaServerParameter parameter : paramList){
            if (StrUtil.isNotBlank(parameter.getNameSpace())){
                String nameSpace = parameter.getNameSpace().startsWith("/") ? parameter.getNameSpace() : "/"+parameter.getNameSpace();
                final SocketIONamespace namespace = server.addNamespace(nameSpace);

                if (parameter.getMessageType().equals(MochaMessageType.SocketJson)){
                    namespace.addEventListener(parameter.getEvent(),   String.class,  new MochaTextJsonListener(parameter.getNameSpace(),  parameter.getEvent()));
                }else {
                    namespace.addEventListener(parameter.getEvent(),   String.class,  new MochaTextListener(parameter.getNameSpace(),  parameter.getEvent()));
                }
            }else {
                if (parameter.getMessageType().equals(MochaMessageType.SocketJson)){
                    server.addEventListener(parameter.getEvent(),   String.class,  new MochaTextJsonListener(parameter.getNameSpace(),  parameter.getEvent()));
                }else {
                    server.addEventListener(parameter.getEvent(),   String.class,  new MochaTextListener(parameter.getNameSpace(),  parameter.getEvent()));
                }
            }
        }

        log.info("Socket start port:{}", port + (StrUtil.isNotEmpty(host) ? " host: "+ host : ""));
        server.start();

    }




    private Configuration buildConfiguration(Integer port, String host) {
        if (null == port) {
            throw new MochaWebsocketException("Server port is null");
        }
        Configuration config = new Configuration();
        config.setHostname(host);
        config.setPort(port);
        config.setBossThreads(1);
        config.setMaxFramePayloadLength(256 * 1024);
        config.setMaxHttpContentLength(256 * 1024);
        return config;
    }


}
